home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Networking / Talking Heads / Sources / ez_adsp ƒ / ez_adsp DRVR.c next >
Encoding:
C/C++ Source or Header  |  1989-12-13  |  15.1 KB  |  712 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3. /*  © 1989 Ricardo Batista */
  4.  
  5.  
  6. #include "ADSP.h"
  7.  
  8. #define        open                0
  9. #define        prime                1
  10. #define        control                2
  11. #define        status                3
  12. #define        close                4
  13.  
  14.  
  15.  
  16. /*
  17.      © 1989 Apple Computer, Inc. by Ricardo Batista
  18.  
  19.                 EZ_ADSP driver interface version 1.0, March 6 1989.
  20.  
  21.     The ez_adsp driver loads itself automatically in any machine, then it loads an
  22.     STR with id 268 to be used as the 'type' registered in the network. STR 269 is
  23.     loaded as the name of a desk accessory to be opened when a connection is
  24.     detected (and the name is not null).  To open the ez_adsp driver issue an
  25.     OpenDriver("\p.ez_adsp",&refNum); call, when you are done with it don't close
  26.     the driver.
  27. */
  28.  
  29.  
  30. /*
  31.     Structure used to give information about a file transfer follows.  The driver
  32.     recognizes a file transfer when two empty messages are sent with the EOM bit
  33.     set and the next message (with the EOM bit set) is the following structure.
  34.     Only the size of the structure is checked and if it matches a file transfer
  35.     is assumed.  Following the file information message is the data fork with the
  36.     EOM bit set at the end, then the resource fork is sent again with the EOM bit
  37.     set at the end.  Notice that if either fork is empty only an EOM bit constitutes
  38.     the message.
  39. */
  40.  
  41.  
  42. typedef struct {
  43.     char    file_name[66];
  44.     OSType     file_creator;
  45.     OSType    file_type;
  46.     long    data_len;
  47.     long    res_len;
  48.     int        finder_flags;
  49.     int        info;
  50. } file_info;
  51.  
  52.                 /* Control call csCode's to the ez_adsp driver */
  53.  
  54.  
  55. #define        openConn            100
  56. #define        closeConn            101
  57. #define        autoFile            102
  58. #define        sendFile            103
  59. #define        disable                104
  60. #define        enable                105
  61. #define        deskFlag            106
  62.  
  63.  
  64.  
  65. /*
  66.     openConn,     opening a connection, csParam[0]-[1] contains an AddrBlock to connect to
  67.     closeConn,     closes a connection and starts waiting for a remote connection if we are
  68.                 enabled to answer a call, default is enabled.
  69.     autoFile,    csParam[0] contains a flag to set the autoFile parameter, if true the
  70.                 driver recognizes a file transfer and saves the received file in the
  71.                 disk the user selects. False by default.
  72.     sendFile,    this takes a pointer to a file name in csParam[0]-[1], and a volume
  73.                 reference number in csParam[2], the file is then transfered to the remote
  74.                 connection.
  75.     disable,    disables answering to a remote connection.
  76.     enable,        enables answering to a remote connection, default.
  77.     deskFlag,    sets the desk accesory opened flag to csParam[0], if false, then as soon
  78.                 as a connection is detected the desk accessory who's name was stored in
  79.                 the resource STR 269 (if any) is opened, then the flag is set to true.
  80. /*
  81.  
  82.  
  83.                 /* Status call csCode's to the ez_adsp driver */
  84.  
  85.  
  86. #define        getBuf                120
  87.  
  88.  
  89. /*
  90.     getBuf,        getBuf returns the number of bytes left to read in csParam[0]-[1],
  91.                 csParam[2] contains the connection state (2 = waiting for a connection,
  92.                 3 = opening a connection, 4 = connection opened, 5 = closing a connection,
  93.                 6 = connection closed and no waiting)
  94.                 csParam[3] conatins the userFlags, csParam[4] the attention code (if any)
  95.                 and csParam[5]-[6] a pointer to the attention data. Normally you will only
  96.                 look at csParam[0]-[1].
  97. */
  98.  
  99.  
  100.  
  101. #define        idealSize        512
  102.  
  103. #define        uPtr        unsigned char *
  104.  
  105.  
  106. DSPParamBlock ADSP;
  107. TRCCB CCB;
  108. int ADSPID;
  109. int mySocket;
  110. long signature;
  111. Boolean deskOpened;
  112. Boolean autoSave;
  113. char OutBuffer[attnBufSize];
  114. char InBuffer[attnBufSize];
  115. char attnBuffer[attnBufSize];
  116. AddrBlock address;
  117. char desk[40];
  118. int emptyEOM;
  119. Boolean canAnswer;
  120. int oldState;
  121.  
  122.  
  123. int main(ioParam* param, DCtlPtr d, int call);
  124. Boolean abort(void);
  125. int InitComm(void);
  126. int OpenComm(Boolean waitForCall);
  127. int CloseComm(void);
  128. int DoName(int Socket);
  129. int file(cntrlParam* p);
  130. int recFile(void);
  131.  
  132.  
  133.  
  134.  
  135. int main(param, d, call)
  136. ioParam *param;
  137. DCtlPtr d;
  138. int call;
  139. {
  140.     int err = 0;
  141.     cntrlParam *p;
  142.     long len;
  143.     WindowPtr w;
  144.  
  145.     if (d->dCtlStorage == 0L) {
  146.         if (call == open) {
  147.             SysBeep(1);
  148.             return(openErr);
  149.         }
  150.         return(openErr);
  151.     }
  152.     if ((call != open) && (signature != 'RICK')) {
  153.         return(notOpenErr);
  154.     }
  155.     switch (call) {
  156.         case open:
  157.             d->dCtlFlags |= dNeedLock | dNeedTime;
  158.             d->dCtlDelay = 25;
  159.             if (signature != 'RICK') {
  160.                 signature = 'RICK';
  161.                 err = OpenDriver("\p.MPP",&ADSPID);
  162.                 if (!err)
  163.                     err = OpenDriver("\p.DSP",&ADSPID);
  164.                 if (err)
  165.                     return(err);
  166.                 err = InitComm();
  167.                 if (!err)
  168.                     err = OpenComm(TRUE);
  169.             }
  170.             break;
  171.         case prime:
  172.             if ((char) (param->ioTrap) == aWrCmd) {
  173.                 ADSP.csCode = dspWrite;
  174.                 ADSP.u.ioParams.reqCount = param->ioReqCount;
  175.                 ADSP.u.ioParams.dataPtr = (uPtr) param->ioBuffer;
  176.                 ADSP.u.ioParams.eom = param->ioPosMode;
  177.                 ADSP.u.ioParams.flush = 0;    /* or ONE ? */
  178.                 err = PBControl(&ADSP,FALSE);
  179.                 param->ioActCount = ADSP.u.ioParams.actCount;
  180.             }
  181.             else
  182.             if ((char) (param->ioTrap) == aRdCmd) {
  183.                 ADSP.csCode = dspRead;
  184.                 ADSP.u.ioParams.reqCount = param->ioReqCount;
  185.                 ADSP.u.ioParams.dataPtr = (uPtr) param->ioBuffer;
  186.                 err = PBControl(&ADSP,FALSE);
  187.                 param->ioActCount = ADSP.u.ioParams.actCount;
  188.                 param->ioPosMode = ADSP.u.ioParams.eom;
  189.                 if (ADSP.u.ioParams.eom && autoSave) {
  190.                     if (emptyEOM > 1) {
  191.                         if (param->ioActCount == sizeof(file_info)) {
  192.                             emptyEOM = 0;
  193.                             d->dCtlFlags -= dNeedTime;
  194.                             err = recFile();
  195.                             d->dCtlFlags |= dNeedLock | dNeedTime;
  196.                             param->ioActCount = 0;
  197.                         }
  198.                     }
  199.                     if (param->ioActCount == 0)
  200.                         emptyEOM++;
  201.                 }
  202.                 else
  203.                     emptyEOM = 0;
  204.             }
  205.             break;
  206.         case control:
  207.             p = (cntrlParam*) param;
  208.             switch (p->csCode) {
  209.                 case openConn:
  210.                     err = CloseComm();
  211.                     BlockMove(&(p->csParam[0]),&address,4L);
  212.                     err = OpenComm(FALSE);
  213.                     if (err)
  214.                         OpenComm(TRUE);
  215.                     else
  216.                         deskOpened = TRUE;
  217.                     break;
  218.                 case closeConn:
  219.                     err = CloseComm();
  220.                     if (!err)
  221.                         err = OpenComm(TRUE);
  222.                     break;
  223.                 case autoFile:
  224.                     autoSave = p->csParam[0];
  225.                     break;
  226.                 case sendFile:
  227.                     d->dCtlFlags -= dNeedTime;
  228.                     err = file(p);
  229.                     d->dCtlFlags |= dNeedLock | dNeedTime;
  230.                     break;
  231.                 case disable:
  232.                     if (CCB.state == sPassive)
  233.                         err = CloseComm();
  234.                     canAnswer = FALSE;
  235.                     break;
  236.                 case enable:
  237.                     canAnswer = TRUE;
  238.                     if (CCB.state == sClosed)
  239.                         err = OpenComm(TRUE);
  240.                     break;
  241.                 case deskFlag:
  242.                     deskOpened = p->csParam[0];
  243.                     break;
  244.                 case accRun:
  245.                     if (!deskOpened) {
  246.                         if ((CCB.state == sOpen) && (oldState != sOpen)) {
  247.                             w = FrontWindow();
  248.                             if (((WindowPeek) w)->windowKind != dBoxProc) {
  249.                                 deskOpened = TRUE;
  250.                                 if (desk[0])
  251.                                     OpenDeskAcc(desk);
  252.                             }
  253.                         }
  254.                     }
  255.                     oldState = CCB.state;
  256.                     if ((CCB.state == sClosed) && canAnswer)
  257.                         err = OpenComm(TRUE);
  258.                     break;
  259.                 default:
  260.                     err = controlErr;
  261.                     break;
  262.             }
  263.             break;
  264.         case status:
  265.             p = (cntrlParam*) param;
  266.             switch (p->csCode) {
  267.                 case getBuf:
  268.                     if (CCB.state == sOpen) {
  269.                         ADSP.csCode = dspStatus;
  270.                         err = PBControl(&ADSP,FALSE);
  271.                         len = ADSP.u.statusParams.recvQPending;
  272.                         BlockMove(&len,&(p->csParam[0]),4L);
  273.                     }
  274.                     else {
  275.                         p->csParam[0] = 0;
  276.                         p->csParam[1] = 0;
  277.                     }
  278.                     p->csParam[2] = CCB.state;
  279.                     p->csParam[3] = CCB.userFlags;
  280.                     p->csParam[4] = CCB.attnCode;
  281.                     CCB.userFlags = 0;
  282.                     BlockMove(&CCB.attnPtr,&(p->csParam[5]),4L);
  283.                     break;
  284.                 default:
  285.                     err = statusErr;
  286.                     break;
  287.             }
  288.             break;
  289.         case close:
  290.             err = CloseComm();
  291.             ADSP.csCode = dspRemove;
  292.             ADSP.u.closeParams.abort = TRUE;
  293.             err = PBControl(&ADSP,FALSE);
  294.             break;
  295.     }
  296.     return(err);
  297.     asm {
  298.         dc.l '© 19'
  299.         dc.l '89 A'
  300.         dc.l 'pple'
  301.         dc.l ' Com'
  302.         dc.l 'pute'
  303.         dc.l 'r, I'
  304.         dc.l 'nc. '
  305.         dc.l 'Rica'
  306.         dc.l 'rdo '
  307.         dc.l 'Bati'
  308.         dc.l 'sta.'
  309.     }
  310. }
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322. int OpenComm(waitForCall)
  323. Boolean waitForCall;
  324. {
  325.     int err = 0, net, node;
  326.  
  327.     ADSP.csCode = dspOpen;
  328.     ADSP.ccbRefNum = CCB.refNum;
  329.     ADSP.u.openParams.localCID = 0;
  330.     ADSP.u.openParams.remoteCID = 0;
  331.     ADSP.u.openParams.remoteAddress = address;
  332.     ADSP.u.openParams.filterAddress.aSocket = 0;
  333.     ADSP.u.openParams.filterAddress.aNode = 0;
  334.     ADSP.u.openParams.filterAddress.aNet = 0;
  335.     ADSP.u.openParams.sendSeq = 0;
  336.     ADSP.u.openParams.sendWindow = idealSize;
  337.     ADSP.u.openParams.recvSeq = 0;
  338.     ADSP.u.openParams.attnSendSeq = 0;
  339.     ADSP.u.openParams.attnRecvSeq = 0;
  340.     ADSP.u.openParams.ocInterval = 6;
  341.     ADSP.u.openParams.ocMaximum = 3;
  342.     if (waitForCall) {
  343.         if (canAnswer) {
  344.             ADSP.u.openParams.remoteAddress.aNet = 0;
  345.             ADSP.u.openParams.remoteAddress.aNode = 0;
  346.             ADSP.u.openParams.remoteAddress.aSocket = 0;
  347.             ADSP.u.openParams.ocMode =     ocPassive;
  348.             err = PBControl(&ADSP,TRUE);
  349.         }
  350.     }
  351.     else {
  352.         err = GetNodeAddress(&node,&net);
  353.         if (net == address.aNet) {
  354.             if ((node == address.aNode) && (CCB.localSocket == address.aSocket))
  355.                 return(-1);
  356.         }
  357.         ADSP.u.openParams.ocMode = ocRequest;
  358.         err = PBControl(&ADSP,FALSE);
  359.     }
  360.     return(err);
  361. }
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376. int InitComm()
  377. {
  378.     int err;
  379.  
  380.     desk[0] = 0;
  381.     emptyEOM = 0;
  382.     deskOpened = autoSave = FALSE;
  383.     canAnswer = TRUE;
  384.     ADSP.ioNamePtr = 0L;
  385.     ADSP.ioCRefNum = ADSPID;
  386.     ADSP.ioCompletion = 0L;
  387.     ADSP.ccbRefNum = 0;
  388.     ADSP.csCode = dspInit;
  389.     ADSP.u.initParams.ccbPtr = &CCB;
  390.     ADSP.u.initParams.userRoutine = 0L;
  391.     ADSP.u.initParams.sendQSize = attnBufSize;
  392.     ADSP.u.initParams.recvQSize = attnBufSize;
  393.     ADSP.u.initParams.sendQueue = (uPtr) &OutBuffer[0];
  394.     ADSP.u.initParams.recvQueue = (uPtr) &InBuffer[0];
  395.     ADSP.u.initParams.attnPtr = (uPtr) &attnBuffer[0];
  396.     ADSP.u.initParams.localSocket = 0;
  397.     CCB.refNum = 0;
  398.     err = PBControl(&ADSP,FALSE);
  399.     CCB.refNum = ADSP.ccbRefNum;
  400.     if (!err)
  401.         DoName(ADSP.u.initParams.localSocket);
  402.     return(err);
  403. }
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413. int DoName(Socket)
  414. int Socket;
  415. {
  416.     StringHandle str = 0L;
  417.     EntityName name;
  418.     long nameSize;
  419.     Ptr rp;
  420.     int err;
  421.     MPPParamBlock p;
  422.     NamesTableEntry *NTPtr;
  423.     int index;
  424.  
  425.     str = (StringHandle) GetString(-16096);
  426.     if (str) {
  427.         HLock(str);
  428.         BlockMove(*str,&(name.objStr[0]),33L);
  429.         HUnlock(str);
  430.         ReleaseResource(str);
  431.     }
  432.     if (name.objStr[0] == 0) {
  433.         name.objStr[0] = 1;
  434.         name.objStr[1] = '?';
  435.     }
  436.     str = (StringHandle) GetString(268);
  437.     if (str) {
  438.         HLock(str);
  439.         BlockMove(*str,&(name.typeStr[0]),33L);
  440.         HUnlock(str);
  441.         ReleaseResource(str);
  442.     }
  443.     str = (StringHandle) GetString(269);
  444.     if (str) {
  445.         HLock(str);
  446.         BlockMove(*str,&(desk[1]),33L);
  447.         HUnlock(str);
  448.         ReleaseResource(str);
  449.         if (desk[1]) {
  450.             desk[0] = desk[1] + 1;
  451.             desk[1] = 0;
  452.         }
  453.     }
  454.     name.zoneStr[0] = 1;
  455.     name.zoneStr[1] = '*';
  456.         nameSize = sizeof(NamesTableEntry);
  457.     asm {
  458.         move.l nameSize,d0
  459.         _NewPtr SYS+CLEAR
  460.         move.l a0,NTPtr
  461.     }
  462.     NTPtr->nteAddress.aSocket = Socket;
  463.     p.NBPinterval = 3;
  464.     p.NBPcount = 3;
  465.     p.NBPverifyFlag = TRUE;
  466.     p.NBPntQElPtr = (Ptr) NTPtr;
  467.     BlockMove(name.objStr,NTPtr->entityData,33L);
  468.     index = name.objStr[0] + 1;
  469.     BlockMove(name.typeStr,&(NTPtr->entityData[index]),33L);
  470.     index += name.typeStr[0] + 1;
  471.     BlockMove(name.zoneStr,&(NTPtr->entityData[index]),33L);
  472.     err = PRegisterName(&p,FALSE);
  473.     while (err == nbpDuplicate) {
  474.         name.objStr[0]++;
  475.         name.objStr[name.objStr[0]] = '1';
  476.         BlockMove(name.objStr,NTPtr->entityData,33L);
  477.         index = name.objStr[0] + 1;
  478.         BlockMove(name.typeStr,&(NTPtr->entityData[index]),33L);
  479.         index += name.typeStr[0] + 1;
  480.         BlockMove(name.zoneStr,&(NTPtr->entityData[index]),33L);
  481.         err = PRegisterName(&p,FALSE);
  482.     }
  483.     return(err);
  484. }
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492. int CloseComm()
  493. {
  494.     ADSP.csCode = dspClose;
  495.     ADSP.u.closeParams.abort = TRUE;
  496.     return(PBControl(&ADSP,FALSE));
  497. }
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504. /*
  505.     The format of a file being sent is two EOM's in a row, then the finder info
  506.     with the EOM bit set, then the data fork, with the EOM at the end and finally
  507.     the resource fork, with the EOM bit set at the end.
  508. */
  509.  
  510.  
  511.  
  512.  
  513. int file(p)
  514. cntrlParam* p;
  515. {
  516.     Ptr file_name;
  517.     int vRefNum, vol = 0, err = 0, refNum;
  518.     long rlen = 0L, dlen = 0L, len;
  519.     char buffer[512];
  520.     file_info f;
  521.     fileParam fp;
  522.  
  523.     BlockMove(&(p->csParam[0]),&file_name,4L);
  524.     vRefNum = p->csParam[2];
  525.     ADSP.csCode = dspWrite;
  526.     ADSP.u.ioParams.reqCount = 5;
  527.     ADSP.u.ioParams.dataPtr = (uPtr) "File:";
  528.     ADSP.u.ioParams.eom = TRUE;
  529.     ADSP.u.ioParams.flush = TRUE;
  530.     err = PBControl(&ADSP,FALSE);            /* Flush whatever data is there */
  531.     if (err)
  532.         return(err);
  533.     ADSP.u.ioParams.reqCount = 0;
  534.     ADSP.u.ioParams.eom = TRUE;                /* write just an EOM */
  535.     err = PBControl(&ADSP,FALSE);
  536.     if (err)
  537.         return(err);
  538.     err = PBControl(&ADSP,FALSE);                /* Once more, another EOM */
  539.     if (err)
  540.         return(err);
  541.     ADSP.u.ioParams.flush = FALSE;
  542.     fp.ioCompletion = 0L;
  543.     fp.ioFVersNum = 0;
  544.     fp.ioFDirIndex = 0;
  545.     fp.ioNamePtr = (StringPtr) file_name;
  546.     fp.ioVRefNum = vRefNum;
  547.     err = PBGetFInfo(&fp,FALSE);
  548.     if (err)
  549.         return(err);
  550.     f.info = 'FT';
  551.     dlen = f.data_len = fp.ioFlLgLen;
  552.     rlen = f.res_len = fp.ioFlRLgLen;
  553.     f.file_type = fp.ioFlFndrInfo.fdType;
  554.     f.file_creator = fp.ioFlFndrInfo.fdCreator;
  555.     f.finder_flags = fp.ioFlFndrInfo.fdFlags;
  556.     BlockMove(file_name,&f.file_name[0],65L);
  557.     ADSP.u.ioParams.reqCount = sizeof(file_info);
  558.     ADSP.u.ioParams.dataPtr = (uPtr) &f;
  559.     ADSP.u.ioParams.eom = TRUE;
  560.     err = PBControl(&ADSP,FALSE);
  561.     if (err)
  562.         return(err);
  563.     err = FSOpen(file_name,vRefNum,&refNum);
  564.     if (err)
  565.         return(err);
  566.     ADSP.u.ioParams.dataPtr = (uPtr) &buffer[0];
  567.     ADSP.u.ioParams.eom = FALSE;
  568.     do {
  569.         if (dlen > 512)
  570.             len = 512;
  571.         else
  572.             len = dlen;
  573.         dlen -= len;
  574.         if (dlen == 0)
  575.             ADSP.u.ioParams.eom = TRUE;
  576.         if (len)
  577.             err = FSRead(refNum,&len,&buffer[0]);
  578.         ADSP.u.ioParams.reqCount = len;
  579.         err = PBControl(&ADSP,FALSE);
  580.         if (err) {
  581.             FSClose(refNum);
  582.             return(err);
  583.         }
  584.     } while (dlen > 0L);
  585.     FSClose(refNum);
  586.     ADSP.u.ioParams.eom = FALSE;
  587.     err = OpenRF(file_name,vRefNum,&refNum);
  588.     if (err)
  589.         return(err);
  590.     do {
  591.         if (rlen > 512)
  592.             len = 512;
  593.         else
  594.             len = rlen;
  595.         rlen -= len;
  596.         if (rlen == 0)
  597.             ADSP.u.ioParams.eom = TRUE;
  598.         if (len)
  599.             err = FSRead(refNum,&len,&buffer[0]);
  600.         ADSP.u.ioParams.reqCount = len;
  601.         err = PBControl(&ADSP,FALSE);
  602.         if (err) {
  603.             FSClose(refNum);
  604.             return(err);
  605.         }
  606.     } while (rlen > 0L);
  607.     FSClose(refNum);
  608.     return(noErr);
  609. }
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621. int recFile()
  622. {
  623.     SFReply reply;
  624.     file_info info;
  625.     long dlen = 0, rlen = 0, len = 0;
  626.     int err, refNum;
  627.     Point where;
  628.     char buffer[512];
  629.     FInfo finder;
  630.  
  631.     where.h = where.v = 100;
  632.     BlockMove(ADSP.u.ioParams.dataPtr,&info,(long) sizeof(file_info));
  633.     SFPutFile(where,"\pSave as :",info.file_name,0L,&reply);
  634.     if (!reply.good)
  635.         return(readErr);
  636.     dlen = info.data_len;
  637.     rlen = info.res_len;
  638.     ADSP.csCode = dspRead;
  639.     ADSP.u.ioParams.dataPtr = (uPtr) buffer;
  640.     err = Create(reply.fName,reply.vRefNum,info.file_creator,info.file_type);
  641.     if (err == dupFNErr) {
  642.         err = FSDelete(reply.fName,reply.vRefNum);
  643.         err = Create(reply.fName,reply.vRefNum,info.file_type,info.file_creator);
  644.     }
  645.     if (err)
  646.         return(err);
  647.     err = FSOpen(reply.fName,reply.vRefNum,&refNum);
  648.     if (err)
  649.         return(err);
  650.     do {
  651.         if (dlen > 512)
  652.             len = 512;
  653.         else
  654.             len = dlen;
  655.         dlen -= len;
  656.         ADSP.u.ioParams.reqCount = len;
  657.         err = PBControl(&ADSP,FALSE);
  658.         if (err) {
  659.             FSClose(refNum);
  660.             return(err);
  661.         }
  662.         if (len)
  663.             err = FSWrite(refNum,&len,&buffer[0]);
  664.     } while (dlen > 0L);
  665.     FSClose(refNum);
  666.     err = OpenRF(reply.fName,reply.vRefNum,&refNum);
  667.     if (err)
  668.         return(err);
  669.     do {
  670.         if (rlen > 512)
  671.             len = 512;
  672.         else
  673.             len = rlen;
  674.         rlen -= len;
  675.         ADSP.u.ioParams.reqCount = len;
  676.         err = PBControl(&ADSP,FALSE);
  677.         if (err) {
  678.             FSClose(refNum);
  679.             return(err);
  680.         }
  681.         if (len)
  682.             err = FSWrite(refNum,&len,&buffer[0]);
  683.     } while (rlen > 0L);
  684.     FSClose(refNum);
  685.     err = GetFInfo(reply.fName,reply.vRefNum,&finder);
  686.     finder.fdFlags = info.finder_flags;
  687.     err = SetFInfo(reply.fName,reply.vRefNum,&finder);
  688.     return(err);
  689. }
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.